<?php
declare (strict_types=1);

namespace app\controller\home;

use app\common\controller\BaseController;
use app\model\admin\Grade;
use app\model\home\MemberWx;
use think\App;
use think\Db;
use WeChatPay\Builder;
use WeChatPay\Crypto\AesGcm;
use app\model\home\Order as orderModel;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
use WeChatPay\Util\PemUtil;

class WxPay extends BaseController
{
    protected $order;

    public function __construct(App $app, orderModel $model)
    {
        parent::__construct($app);
        $this->order = $model;
    }

    /**
     * @return array|void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * 支付
     */
    public function pay()
    {
        //获取当前用户openid
        $openid = MemberWx::where('member_id', $this->memberId)->value('openid');
        $where = [];
        $orderId = input('order_id/d');
        $orderNo = input('order_no');
        if (!$orderId && !$orderNo) {
            return $this->returnError(-1, [], '订单ID或订单编号必须存在一个');
        }
        !empty($orderId) && $where['order_id'] = $orderId;
        !empty($orderNo) && $where['order_no'] = $orderNo;
        $where['pay_status'] = 0;
        $orderInfo = \app\model\home\Order::where($where)->find();
        if (!$orderInfo) {
            return $this->returnError(-1, [], '订单不存在');
        }
        if ($orderInfo['pay_price'] <= 0) {
            return $this->returnError(-1, [], '订单支付金额不合法');
        }
        $PaymentAmount = bcmul($orderInfo['pay_price'], (string)100, 0);
        $merchantId = config('wx.wx_pay.mch_id');
        $merchantPrivateKeyFilePath = public_path() . 'cert/apiclient_key.pem';
        //加载商户私钥
        $merchantPrivateKeyInstance = PemUtil::loadPrivateKey($merchantPrivateKeyFilePath);
        // 加载商户证书
        $merchantCertificateFilePath = public_path() . 'cert/apiclient_cert.pem';
        $merchantCertificateInstance = PemUtil::loadCertificate($merchantCertificateFilePath);
        // 解析商户证书序列号
        $merchantCertificateSerial = PemUtil::parseCertificateSerialNo($merchantCertificateInstance);
        // 平台证书，可由下载器 `./bin/CertificateDownloader.php` 生成并假定保存为 `/path/to/wechatpay/cert.pem`
        $platformCertificateFilePath = public_path() . 'cert/cert.pem';
        // 加载平台证书
        $platformCertificateInstance = PemUtil::loadCertificate($platformCertificateFilePath);
        // 解析平台证书序列号
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateInstance);

        // 工厂方法构造一个实例
        $instance = Builder::factory([
            'mchid' => $merchantId,
            'serial' => $merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs' => [
                $platformCertificateSerial => $platformCertificateInstance,
            ],
        ]);
        try {
            $resp = $instance
                ->chain('v3/pay/transactions/jsapi')
                ->post(['json' => [
                    'mchid' => config('wx.wx_pay.mch_id'),
                    'out_trade_no' => $orderInfo['order_no'],
                    'appid' => config('wx.wx_pay.app_id'),
                    'description' => 'KiraPark',
                    'notify_url' => config('wx.wx_pay.notify'),
                    'amount' => [
                        'total' => (int)$PaymentAmount,
                        'currency' => 'CNY'
                    ],
                    'payer' => [
                        'openid' => $openid
                    ]
                ]]);
            $resultCode = $resp->getStatusCode();
            if ($resultCode == 200) {
                $result_data = json_decode((string)$resp->getBody(), true);
                $arouse_data = [
                    'appId' => config('wx.wx_pay.app_id'),
                    'timeStamp' => (string)Formatter::timestamp(),
                    'nonceStr' => Formatter::nonce(),
                    'package' => "prepay_id=" . $result_data['prepay_id'],
                ];
                $arouse_data['sign'] = Rsa::sign(
                    Formatter::joinedByLineFeed(...array_values($arouse_data)),
                    $merchantPrivateKeyInstance
                );
                return $this->returnRight($arouse_data);
            }
        } catch (\Exception $ex) {
            // 进行错误处理
            if ($ex instanceof \GuzzleHttp\Exception\RequestException && $ex->hasResponse()) {
                return $this->returnException($ex);
            }
        }
    }

    /**
     *
     * 回调地址
     */
    public function notify()
    {
        $orderNo = input('order_no');
        $payTime = input('pay_time');
        if (empty($orderNo)) {
            return $this->returnError(-1, [], '订单号不存在');
        }
        if (empty($payTime)) {
            return $this->returnError(-1, [], '支付时间不存在');
        }
        $updateData = [
            'pay_status' => 1,
            'pay_time' => $payTime
        ];
        $where[] = ['order_no', 'in', $orderNo];
        $orderArr = $this->order->where([$where])
            ->field('id,member_id,order_no,re_id,store_id,order_type,book_id,pay_price,order_count')
            ->select();
        //开启事务
        try {
            $this->order->startTrans();
            foreach ($orderArr as $orderInfo) {
                if ($orderInfo['order_type'] == 1 || $orderInfo['order_type'] == 2) {
                    $updateData['book_id'] = $orderInfo['book_id'];
                    \app\model\home\Book::update(['status' => 1], ['id' => $orderInfo['book_id']]);
                    //发送短信
                    if ($orderInfo['order_type'] == 1) {
                        $memberInfo = \app\common\model\Member::where('member_id', $orderInfo['member_id'])
                            ->field('phone,nickname')
                            ->find();
                        TxSms::send($memberInfo['phone'], "1324102", $memberInfo['nickname']);
                    }
                }
                \app\model\home\Order::update($updateData, ['order_no' => $orderInfo['order_no']]);
                $orderType = $orderInfo['order_type'];
                if ($orderType == 3 || $orderType == 8) {
                    $propType = input('prop_type', 1);
                    $propId = input('prop_id', 0);
                    if ($orderType == 3) {
                        $prop = [
                            'prop_id' => $propId,
                            'prop_type' => $propType,
                            'assistant_id' => $orderInfo['re_id'],
                            'member_id' => $this->memberId,
                            'prop_count' => $orderInfo['order_count']
                        ];
                        \app\model\home\PropUse::create($prop);
                    }
                    //使用赠送道具
                    if ($orderType == 8) {
                        //减掉数量
                        $where['prop_id'] = $propId;
                        $where['member_id'] = $this->memberId;
                        $where['prop_type'] = $propType;
                        $propCount = \app\model\home\PropMember::where($where)->value('prop_count');
                        $diffCount = $propCount - $orderInfo['order_count'];
                        $this->where($where)->save(['prop_count' => $diffCount]);
                    }
                    //更新等级和星
                    $this->updateGrade($orderInfo['re_id'], $propType, $orderInfo['order_count']);
                }
                //年卡支付
                if ($orderType == 5) {
                    \app\model\home\Assistant::update(['is_vip' => 1], ['member_id' => $this->memberId]);
                }
                //充值
                if ($orderType == 7) {
                    $totalPrice = intval($orderInfo['pay_price'] * 100) * $orderInfo['order_count'];
                    $balance = \app\common\model\Member::where('member_id', $this->memberId)->value('balance');
                    $nowTotal = ($totalPrice + (floatval($balance) * 100)) / 100;
                    \app\common\model\Member::update(['balance' => $nowTotal], ['member_id' => $this->memberId]);
                }
            }
            $this->order->commit();
        } catch (\Exception $ex) {
            $this->order->rollback();
            if ($ex->getMessage() == "升星失败") {
                return $this->returnError(45);
            } else {
                return $this->returnException($ex);
            }
        }

        return $this->returnSucc();
    }

    /**
     * @param $assistantId
     * @param $prop_type
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * 更新等级和星
     */
    public function updateGrade($assistantId, $prop_type, $orderCount)
    {
        $assInfo = \app\model\home\Assistant::where('id', $assistantId)->field('grade_id,star')->find();
        //根据grade_id获取对应等级信息
        $gradeName = Grade::where('id', $assInfo['grade_id'])->value('grade_name');
        switch ($prop_type) {
            //升级
            case 1:
                //UR是最高，不能升级了
                if ($gradeName == 'UR') {
                    $name = 'UR';
                } else {
                    $name = $this->getUpGradeName($gradeName, $orderCount);
                }
                break;
            //升星
            case 2:
                //当前助教等级不是UR
                if ($gradeName != 'UR' && $assInfo['star'] == 6) {
                    $name = $this->getUpGradeName($gradeName, $orderCount);
                    $star = 0;
                } else {
                    $success = $this->getRate($assInfo['star']);
                    if (empty($success)) {
                        // 抛出 HTTP 异常
                        // 抛出404异常
                        abort(404, '升星失败');
                    } else {
                        $star = $assInfo['star'] + 1;
                    }
                }
                break;
            //降级
            case 3:
                //R是最低，不能降级了
                if ($gradeName == 'R') {
                    $name = 'R';
                } else {
                    $name = $this->getDownGrade($gradeName, $orderCount);
                }
                break;
            //降星
            default:
                if ($assInfo['star'] == 0 && $gradeName != 'R') {
                    $name = $this->getDownGrade($gradeName, $orderCount);
                    $star = 6;
                } else {
                    $star = $assInfo['star'] - 1;
                }
        }
        $updateData = [];
        //更新最终的星跟等级
        if (!empty($name)) {
            $grade_id_new = Grade::where('grade_name', $name)->value('id');
            $updateData['grade_id'] = $grade_id_new;
        }
        //升星
        if ($prop_type == 2 && empty($star)) {
            $updateData['star'] = 0;
        }
        !empty($star) && $updateData['star'] = $star;
        \app\model\home\Assistant::update($updateData, ['id' => $assistantId]);
    }

    /**
     * @param $gradeName
     * @return string
     * 获取上级
     */
    public function getUpGradeName($gradeName, $orderCount)
    {
        $upGrade = '';
        switch ($orderCount) {
            //数量是2
            case 2:
                $gradeName == 'R' && $upGrade = 'SSR';
                $gradeName == 'SR' && $upGrade = 'UR';
                $gradeName == 'SSR' && $upGrade = 'UR';
                $gradeName == 'UR' && $upGrade = 'UR';
                break;
            case 3:
                $gradeName == 'R' && $upGrade = 'UR';
                $gradeName == 'SR' && $upGrade = 'UR';
                $gradeName == 'SSR' && $upGrade = 'UR';
                $gradeName == 'UR' && $upGrade = 'UR';
                break;
            default:
                $gradeName == 'R' && $upGrade = 'SR';
                $gradeName == 'SR' && $upGrade = 'SSR';
                $gradeName == 'SSR' && $upGrade = 'UR';
                $gradeName == 'UR' && $upGrade = 'UR';
        }
        return $upGrade;
    }

    /**
     * @param $gradeName
     * @return string
     * 获取下级
     */
    public function getDownGrade($gradeName, $orderCount)
    {
        $downGrade = '';
        //因为降级必须一次用3个道具
        $orderCount = floor($orderCount / 3);
        switch ($orderCount) {
            //数量是2
            case 2 or 3:
                $gradeName == 'R' && $downGrade == 'R';
                $gradeName == 'SR' && $downGrade == 'R';
                $gradeName == 'SSR' && $downGrade == 'R';
                $gradeName == 'UR' && $downGrade == 'UR';
                break;
            case 1:
                $gradeName == 'R' && $downGrade == 'R';
                $gradeName == 'SR' && $downGrade == 'R';
                $gradeName == 'SSR' && $downGrade == 'SR';
                //UR不能被降级
                $gradeName == 'UR' && $downGrade == 'UR';
                break;
            default:
                //连降3级
                $downGrade = "R";
        }
        return $downGrade;
    }

    /**
     * @param $star
     * @return int
     * 升星概率
     */
    public function getRate($star)
    {
        $rand = mt_rand(0, 10);
        switch ($star) {
            case 2:
                if ($rand >= 8 && $rand <= 10) {
                    $success = 0;
                } else {
                    $success = 1;
                }
                break;
            case 3:
                if ($rand >= 6 && $rand <= 10) {
                    $success = 0;
                } else {
                    $success = 1;
                }
                break;
            case 4:
                if ($rand >= 4 && $rand <= 10) {
                    $success = 0;
                } else {
                    $success = 1;
                }
                break;
            case 5:
                if ($rand >= 2 && $rand <= 10) {
                    $success = 0;
                } else {
                    $success = 1;
                }
                break;
            default:
                $success = 1;
        }
        return $success;
    }
}
